import { objectToString, objectToStringFormat, queue } from "../../shared";
import { AbstractQueue, IQueueConstructor } from "./queue-type";
/**
 * 队列构造器
 */
export interface QueueConstructor<T> extends IQueueConstructor<T> {
  new (size: number): Queue<T>;
  readonly [Symbol.species]: QueueConstructor<T>;
  readonly prototype: Queue<T>;
  isQueue<T>(obj: unknown): obj is Queue<T>;
  of<T>(...datas: T[]): Queue<T>;
  from<T>(datas: T[]): Queue<T>;
}
/**
 * 判断是否是队列
 * @param obj 任意对象
 */
export function isQueue<T>(obj: unknown): obj is Queue<T> {
  return obj instanceof Queue;
}
/**
 * 队列
 */
export class Queue<T> extends AbstractQueue<T> {
  static [Symbol.hasInstance](instance): boolean {
    return objectToString(instance) === objectToStringFormat(queue);
  }
  static from<T>(datas: T[]): Queue<T> {
    const queue: Queue<T> = new Queue<T>(datas.length);
    for (const data of datas) queue.enQueue(data);
    return queue;
  }
  static of<T>(...datas: T[]): Queue<T> {
    return this.from(datas);
  }
  static isQueue<T>(obj: unknown): obj is Queue<T> {
    return isQueue(obj);
  }
  static get [Symbol.species](): QueueConstructor<any> {
    return Queue;
  }
  [Symbol.toStringTag] = queue;
  constructor(capacity: number) {
    super(capacity);
  }
  enQueue(element: T): void {
    this.checkEnQueue();
    this._list.push(element);
  }
  deQueue(): T {
    this.checkDeQueue();
    return this._list.shift() as T;
  }
}
